package registration.adventurezone.thevine.com;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.StringWriter;
import java.util.ArrayList;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;
import org.xml.sax.SAXException;


import android.os.Environment;
import android.util.Log;

import registration.adventurezone.thevine.com.Constants.ChildrenFilter;

public class XMLResourceHandler {
	
	private static XMLResourceHandler _instance;
	private static File childrenDatabaseFile;
	private static File idStorageFile;
	private static final String DB_FILE_NAME = "children_database.xml";
	private static final String ID_FILE_NAME = "idTracker.txt";
	private ArrayList<DBChild> children;
	private static Document doc;
	
	protected XMLResourceHandler()
	{
	}

	/**
	 * Requests the instance of the XMLResourceHandler and creates it
	 * if it does not exist.
	 *
	 * @return Returns the single instance of the XMLResourceHandler
	 */
	static synchronized public XMLResourceHandler getInstance()
	{
	    if (_instance == null) {
	      _instance = new XMLResourceHandler();
	      init();
	    }
	    return _instance;
	}
	
	public static void init(){
		File dataStorageDir = new File(Environment.getExternalStorageDirectory(), "AZReg");
    	childrenDatabaseFile = new File(dataStorageDir.getPath() + File.separator + DB_FILE_NAME);
    	doc = getDomElement(childrenDatabaseFile);
    	
    	idStorageFile = new File(dataStorageDir.getPath() + File.separator + ID_FILE_NAME);
	}
	private void reloadFile(){
		File dataStorageDir = new File(Environment.getExternalStorageDirectory(), "AZReg");
    	childrenDatabaseFile = new File(dataStorageDir.getPath() + File.separator + DB_FILE_NAME);
    	doc = getDomElement(childrenDatabaseFile);
	}
	private boolean checkFileExists() {
    	File dataStorageDir = new File(Environment.getExternalStorageDirectory(), "AZReg");
        // This location works best if you want the data to be shared
        // between applications and persist after your app has been uninstalled.

        // Create the storage directory if it does not exist
        if (! dataStorageDir.exists()){
            if (! dataStorageDir.mkdirs()){
                Log.d("ChildDatabase", "failed to create directory");
                return false;
            }
        }
        childrenDatabaseFile = new File(dataStorageDir.getPath() + File.separator + DB_FILE_NAME);
        
        if(!childrenDatabaseFile.exists()) {
        	return false;
        }
        return true;
    }
	
	public String formatData2XML(DBChild data) {
    	try {
            /////////////////////////////
            //Creating an empty XML Document

            //We need a Document
            DocumentBuilderFactory dbFac = DocumentBuilderFactory.newInstance();
            DocumentBuilder docBuilder = dbFac.newDocumentBuilder();
            Document doc;

            ////////////////////////
            //Creating the XML tree

            //create the root element and add it to the document
            
            Element children;
            if(checkFileExists()) {
            	doc = (Document) docBuilder.parse(childrenDatabaseFile);
                children = doc.getDocumentElement();
            }
            else {
            	doc = docBuilder.newDocument();
            	children = doc.createElement("children");
            	doc.appendChild(children);
            }
            

            //create child element, add an attribute, and add to root
            Element child = doc.createElement("child");
            Element childName = doc.createElement("child-name");
            childName.setAttribute("first", data.getChildFirst());
            childName.setAttribute("last", data.getChildLast());
            child.appendChild(childName);
            
            Text text;
            Element idNode = doc.createElement("id");
            if(data.getID() == -1) {
            	int temp = loadID()+1;
            	writeID(temp);
            	String id = String.valueOf(temp);            	
            	text = doc.createTextNode(id);
            }
            else {
            	text = doc.createTextNode(String.valueOf(data.getID()));
            }
            idNode.appendChild(text);
            child.appendChild(idNode);
            

            Element genderNode = doc.createElement("gender");
            text = doc.createTextNode(data.getGender());
            genderNode.appendChild(text);
            child.appendChild(genderNode);
            
            Element dateOfBith = doc.createElement("dob");
            dateOfBith.setAttribute("month", String.valueOf(data.getDob()[0]));
            dateOfBith.setAttribute("day", String.valueOf(data.getDob()[1]));
            dateOfBith.setAttribute("year", String.valueOf(data.getDob()[2]));
            child.appendChild(dateOfBith);
            
            Element allergiesNode = doc.createElement("allergies");
            text = doc.createTextNode(data.getAllergies());
            allergiesNode.appendChild(text);
            child.appendChild(allergiesNode);
            
            Element parentName = doc.createElement("parent-name");
            parentName.setAttribute("first", data.getParentFirst());
            parentName.setAttribute("last", data.getParentLast());
            child.appendChild(parentName);
            
            Element phoneNode = doc.createElement("phone");
            text = doc.createTextNode(data.getPhone());
            phoneNode.appendChild(text);
            child.appendChild(phoneNode);
            
            Element churchPhoneNode = doc.createElement("church-phone");
            text = doc.createTextNode(data.getChurchPhone());
            churchPhoneNode.appendChild(text);
            child.appendChild(churchPhoneNode);
            
            Element churchPrefNode = doc.createElement("church-pref");
            text = doc.createTextNode(data.getChurchPref());
            churchPrefNode.appendChild(text);
            child.appendChild(churchPrefNode);
            
            Element addressNode = doc.createElement("address");
            text = doc.createTextNode(data.getAddress());
            addressNode.appendChild(text);
            child.appendChild(addressNode);
            
            Element cityNode = doc.createElement("city");
            text = doc.createTextNode(data.getCity());
            cityNode.appendChild(text);
            child.appendChild(cityNode);
            
            Element zipNode = doc.createElement("zip");
            text = doc.createTextNode(data.getZip());
            zipNode.appendChild(text);
            child.appendChild(zipNode);
            
            Element checkedIn = doc.createElement("checkedIn");
            text = doc.createTextNode("false");
            checkedIn.appendChild(text);
            child.appendChild(checkedIn);
            
            Element guardians = doc.createElement("guardians");     
            
            for(Guardian guardian : data.getGuardians()){
            	Element guardianName = doc.createElement("guardian-name");
            	guardianName.setAttribute("first", guardian.getFirst());
            	guardianName.setAttribute("last", guardian.getLast());
                guardians.appendChild(guardianName);
            }
            child.appendChild(guardians);
            
            children.appendChild(child);

            /////////////////
            //Output the XML

            //set up a transformer
            TransformerFactory transfac = TransformerFactory.newInstance();
            Transformer trans = transfac.newTransformer();
            trans.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
            trans.setOutputProperty(OutputKeys.INDENT, "yes");

            //create string from xml tree
            StringWriter sw = new StringWriter();
            StreamResult result = new StreamResult(sw);
            DOMSource source = new DOMSource(doc);
            trans.transform(source, result);
            String xmlString = sw.toString();

            return xmlString;

        } catch (Exception e) {
        	throw new RuntimeException(e);
        }
		
    }
	
	public void writeXML2File(String newChildXML) {
    	// write on SD card file data in the text box
		try {
			childrenDatabaseFile.createNewFile();

            FileOutputStream fOut = new FileOutputStream(childrenDatabaseFile);
			OutputStreamWriter myOutWriter = new OutputStreamWriter(fOut);
			myOutWriter.append(newChildXML);
			myOutWriter.close();
			fOut.close();
			
			Log.d("IO: ", "Done writing XML to SD");
			reloadFile();
		} catch (Exception e) {
			Log.e("Error:" , e.getMessage());
		}
	}
	
	public String writeDocToXMLString(){
    	/////////////////
	    //Output the XML
	
	    //set up a transformer
    	try {
	    TransformerFactory transfac = TransformerFactory.newInstance();
	    Transformer trans = null;
		trans = transfac.newTransformer();
	    trans.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
	    trans.setOutputProperty(OutputKeys.INDENT, "yes");
	
	    //create string from xml tree
	    StringWriter sw = new StringWriter();
	    StreamResult result = new StreamResult(sw);
	    DOMSource source = new DOMSource(doc);
	    
		trans.transform(source, result);
		String xmlString = sw.toString();
	    
	    return xmlString;
	    } catch (TransformerException e) {
			e.printStackTrace();
		}
		return null;
	    
    }
    public void writeXMLToMem(String xml) {
    	// write on SD card file data in the text box
		try {
			childrenDatabaseFile.createNewFile();

            FileOutputStream fOut = new FileOutputStream(childrenDatabaseFile, false);
			OutputStreamWriter myOutWriter = new OutputStreamWriter(fOut);
			myOutWriter.append(xml);
			myOutWriter.close();
			fOut.close();
			//Toast.makeText(getBaseContext(),
			//			"Done writing SD 'children_database.xml'",
			//			Toast.LENGTH_SHORT).show();
		} catch (Exception e) {
			//	Toast.makeText(getBaseContext(), e.getMessage(),
			//			Toast.LENGTH_SHORT).show();
		}
    }
    public void writeID(int id) {
    	// write on SD card file data in the text box
		try {
			idStorageFile.createNewFile();

            FileOutputStream fOut = new FileOutputStream(idStorageFile, false);
			OutputStreamWriter myOutWriter = new OutputStreamWriter(fOut);
			myOutWriter.append(String.valueOf(id));
			myOutWriter.close();
			fOut.close();
			//Toast.makeText(getBaseContext(),
			//			"Done writing SD 'children_database.xml'",
			//			Toast.LENGTH_SHORT).show();
		} catch (Exception e) {
			//	Toast.makeText(getBaseContext(), e.getMessage(),
			//			Toast.LENGTH_SHORT).show();
		}
    }
    public int loadID() {
    	String id = "";
    	try {
    	    BufferedReader br = new BufferedReader(new FileReader(idStorageFile));
    	    id = br.readLine();
    	}
    	catch (IOException e) {
    	    Log.e("Error: ", e.getMessage());
    	}
    	return Integer.parseInt(id);
    }
    public static Document getDomElement(File xmlFile){
        Document doc = null;
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        try {
 
            DocumentBuilder db = dbf.newDocumentBuilder();
            doc = db.parse(xmlFile); 
 
            } catch (ParserConfigurationException e) {
                Log.e("Error: ", e.getMessage());
                return null;
            } catch (SAXException e) {
                Log.e("Error: ", e.getMessage());
                return null;
            } catch (IOException e) {
                Log.e("Error: ", e.getMessage());
                return null;
            }
                // return DOM
            return doc;
    }
    
    public ArrayList<DBChild> getChildrenByStatus(ChildrenFilter filter) {
    	ArrayList<DBChild> children = new ArrayList<DBChild>();
    	NodeList childNodeList = doc.getElementsByTagName("child-name");
    	NodeList idList = doc.getElementsByTagName("id");
    	NodeList checkedInList = doc.getElementsByTagName("checkedIn");
    	
    	switch(filter) {
    		case ALL:
    			for (int i=0;i<childNodeList.getLength();i++) {
    	    		int id = Integer.parseInt(idList.item(i).getTextContent());
    	    		children.add(new DBChild(childNodeList.item(i).getAttributes().getNamedItem("first").getNodeValue(),
    							childNodeList.item(i).getAttributes().getNamedItem("last").getNodeValue(), id));

    	    	}
    			break;
    		case CHECKED_OUT:
    			for (int i=0;i<childNodeList.getLength();i++) {
    	    		int id = Integer.parseInt(idList.item(i).getTextContent());
    	    		if(checkedInList.item(i).getTextContent().equals("false")) {
    	    			children.add(new DBChild(childNodeList.item(i).getAttributes().getNamedItem("first").getNodeValue(),
    								childNodeList.item(i).getAttributes().getNamedItem("last").getNodeValue(), id));
    				}
    	    	}
    			break;
    		case CHECKED_IN:
    			NodeList guardiansNode = doc.getElementsByTagName("guardians");
    			for (int i=0;i<childNodeList.getLength();i++) {
    	    		int id = Integer.parseInt(idList.item(i).getTextContent());
    	    		if(checkedInList.item(i).getTextContent().equals("true")) {
    	    			DBChild temp = new DBChild(childNodeList.item(i).getAttributes().getNamedItem("first").getNodeValue(),
								childNodeList.item(i).getAttributes().getNamedItem("last").getNodeValue(), id);
    	    			Node guardians = guardiansNode.item(i);
    	    			NodeList guardianNames = guardians.getChildNodes();
    	    			ArrayList<Guardian> guardiansList = new ArrayList<Guardian>();
    	    			for(int j = 0; j < guardianNames.getLength(); j++) {
    						if(guardianNames.item(j).getNodeName().equals("guardian-name")) {
    							Guardian g = new Guardian(guardianNames.item(j).getAttributes().getNamedItem("first").getNodeValue(), guardianNames.item(j).getAttributes().getNamedItem("last").getNodeValue());
    							guardiansList.add(g);
    						}
    					}
    	    			temp.setGuardians(guardiansList);
    	    			children.add(temp);			
    	    		}
    	    	}
    			break;
    	}
    	
    	return children;
    }
    
    public void checkInSelectedChildren(ArrayList<DBChild> children) {
    	NodeList idList = doc.getElementsByTagName("id");
    	NodeList checkedInList = doc.getElementsByTagName("checkedIn");
    	
    	for( DBChild child : children) {
    		for(int i=0;i<idList.getLength();i++) {
				if(child.getID() == Integer.parseInt(idList.item(i).getTextContent())){
					checkedInList.item(i).setTextContent("true");
				}
			}
    	}
    }
    public void checkOutSelectedChildren(ArrayList<DBChild> children) {
    	NodeList idList = doc.getElementsByTagName("id");
    	NodeList checkedInList = doc.getElementsByTagName("checkedIn");
    	
    	for( DBChild child : children) {
    		for(int i=0;i<idList.getLength();i++) {
				if(child.getID() == Integer.parseInt(idList.item(i).getTextContent())){
					checkedInList.item(i).setTextContent("false");
				}
			}
    	}
    }
    public void updateChildData(DBChild child) {
    	NodeList idList = doc.getElementsByTagName("id");
    	for(int k=0; k<idList.getLength(); k++) {
    		if(child.getID() == Integer.parseInt(idList.item(k).getTextContent())){
    			Node currChildNode = idList.item(k).getParentNode();
    			NodeList dataNodes = currChildNode.getChildNodes();
    			for(int i = 0; i < dataNodes.getLength(); i++) {
    				if(dataNodes.item(i).getNodeName().equals("child-name")) {					
    					dataNodes.item(i).getAttributes().getNamedItem("first").setNodeValue(child.getChildFirst());
    					dataNodes.item(i).getAttributes().getNamedItem("last").setNodeValue(child.getChildLast());
    	
    				}
    				
    				else if(dataNodes.item(i).getNodeName().equals("gender")) {
    					dataNodes.item(i).setNodeValue(child.getGender());
    				}
    				
    				else if(dataNodes.item(i).getNodeName().equals("dob")) {
    					int[] dob = child.getDob(); 
    					dataNodes.item(i).getAttributes().getNamedItem("month").setNodeValue(String.valueOf(dob[0]));
    					dataNodes.item(i).getAttributes().getNamedItem("day").setNodeValue(String.valueOf(dob[1]));
    					dataNodes.item(i).getAttributes().getNamedItem("year").setNodeValue(String.valueOf(dob[2]));
    				}
    				
    				else if(dataNodes.item(i).getNodeName().equals("allergies")) {
    					dataNodes.item(i).setNodeValue(child.getAllergies());
    				}
    				
    				else if(dataNodes.item(i).getNodeName().equals("parent-name")) {
    					dataNodes.item(i).getAttributes().getNamedItem("first").setNodeValue(child.getParentFirst());
    					dataNodes.item(i).getAttributes().getNamedItem("last").setNodeValue(child.getParentLast());
    				}
    				
    				else if(dataNodes.item(i).getNodeName().equals("phone")) {
    					dataNodes.item(i).setNodeValue(child.getPhone());
    				}
    				else if(dataNodes.item(i).getNodeName().equals("church-phone")) {
    					dataNodes.item(i).setNodeValue(child.getChurchPhone());
    				}
    				else if(dataNodes.item(i).getNodeName().equals("church-pref")) {
    					dataNodes.item(i).setNodeValue(child.getChurchPref());
    				}
    				else if(dataNodes.item(i).getNodeName().equals("address")) {
    					dataNodes.item(i).setNodeValue(child.getAddress());
    				}
    				else if(dataNodes.item(i).getNodeName().equals("city")) {
    					dataNodes.item(i).setNodeValue(child.getCity());
    				}
    				else if(dataNodes.item(i).getNodeName().equals("zip")) {
    					dataNodes.item(i).setNodeValue(child.getZip());
    				}
    				else if(dataNodes.item(i).getNodeName().equals("guardians")) {
    					//Right now I'm just clobbering XML guardians with what's in the DBChild object
    					//TODO: Fix this so that I'm not clobbering data, but putting everything in the right place.
    					NodeList guardians = dataNodes.item(i).getChildNodes();
    					
    					int guardianCounter = 0;
    					for(int j=0;j<guardians.getLength(); j++) {
    						if(guardians.item(j).getNodeName().equals("guardian-name")) {
    							guardians.item(j).getAttributes().getNamedItem("first").setNodeValue(child.getGuardians().get(guardianCounter).getFirst());
    							guardians.item(j).getAttributes().getNamedItem("last").setNodeValue(child.getGuardians().get(guardianCounter).getLast());
    							guardianCounter++;
    						}
    					}
    				}
    									
    			}
    			break;
    		}
    	}
    }
    public ArrayList<DBChild> fullInspectSelectedChildren(ArrayList<DBChild> children) {
    	NodeList idList = doc.getElementsByTagName("id");
    	ArrayList<DBChild> retList = new ArrayList<DBChild>();
    	
    	for(DBChild selectedChild:children) {
			Node currChildNode = null;
			DBChild currChild = new DBChild();
			for(int i = 0; i < idList.getLength(); i++) {
				if(Integer.parseInt(idList.item(i).getTextContent()) == selectedChild.getID()) {
					currChildNode = idList.item(i).getParentNode();
					break;
				}
			}
			
			NodeList dataNodes = currChildNode.getChildNodes();
			for(int i = 0; i < dataNodes.getLength(); i++) {
				if(dataNodes.item(i).getNodeName().equals("id")){
					currChild.setID(Integer.parseInt(dataNodes.item(i).getTextContent()));
				}
				if(dataNodes.item(i).getNodeName().equals("child-name")) {					
					currChild.setChildFirst(dataNodes.item(i).getAttributes().getNamedItem("first").getNodeValue());
					currChild.setChildLast(dataNodes.item(i).getAttributes().getNamedItem("last").getNodeValue());
	
				}
				else if(dataNodes.item(i).getNodeName().equals("gender")) {
					currChild.setGender(dataNodes.item(i).getTextContent());
				}
				else if(dataNodes.item(i).getNodeName().equals("dob")) {
					int month = Integer.parseInt(dataNodes.item(i).getAttributes().getNamedItem("month").getNodeValue());
					int day = Integer.parseInt(dataNodes.item(i).getAttributes().getNamedItem("day").getNodeValue());
					int year = Integer.parseInt(dataNodes.item(i).getAttributes().getNamedItem("year").getNodeValue());
					currChild.setDob(new int[]{month,day,year});
				}
				else if(dataNodes.item(i).getNodeName().equals("allergies")) {
					currChild.setAllergies(dataNodes.item(i).getTextContent());
				}
				else if(dataNodes.item(i).getNodeName().equals("parent-name")) {
					currChild.setParentFirst(dataNodes.item(i).getAttributes().getNamedItem("first").getNodeValue());
					currChild.setParentLast(dataNodes.item(i).getAttributes().getNamedItem("last").getNodeValue());
				}
				else if(dataNodes.item(i).getNodeName().equals("phone")) {
					currChild.setPhone(dataNodes.item(i).getTextContent());
				}
				else if(dataNodes.item(i).getNodeName().equals("church-phone")) {
					currChild.setChurchPhone(dataNodes.item(i).getTextContent());
				}
				else if(dataNodes.item(i).getNodeName().equals("church-pref")) {
					currChild.setChurchPref(dataNodes.item(i).getTextContent());
				}
				else if(dataNodes.item(i).getNodeName().equals("address")) {
					currChild.setAddress(dataNodes.item(i).getTextContent());
				}
				else if(dataNodes.item(i).getNodeName().equals("city")) {
					currChild.setCity(dataNodes.item(i).getTextContent());
				}
				else if(dataNodes.item(i).getNodeName().equals("zip")) {
					currChild.setZip(dataNodes.item(i).getTextContent());
				}
				else if(dataNodes.item(i).getNodeName().equals("guardians")) {
					NodeList guardians = dataNodes.item(i).getChildNodes();
					ArrayList<Guardian> dbGuardians = new ArrayList<Guardian>();
					for(int j=0;j<guardians.getLength(); j++) {
						if(guardians.item(j).getNodeName().equals("guardian-name")) {
							Guardian g = new Guardian(guardians.item(j).getAttributes().getNamedItem("first").getNodeValue(),
									guardians.item(j).getAttributes().getNamedItem("last").getNodeValue());
							dbGuardians.add(g);
						}
					}
					currChild.setGuardians(dbGuardians);
				}					
			}
			retList.add(currChild);
	    }
    	return retList;
    }

}